package dog.gui.appointmentView;

import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import javax.swing.*;

import constants.CHANGE;
import constants.STATUS;
import constants.TYPE;
import containers.Appointment;
import containers.Message;
import dog.gui.MessagePanel;
import dog.gui.NewsPanel;
import dog.model.Model;

@SuppressWarnings("serial")
public class AppointmentPanel extends JPanel implements PropertyChangeListener, ActionListener{
	
	private Appointment oldAppointment;
	private Appointment newAppointment;
	//private Appointment appointment;
	private Model model;
	private boolean isEditable;
	private boolean isOwner;
	
	private AppointmentInfoPanel infoPanel;
	private JButton createButton;
	private JButton editButton;
	private JButton backButton;
	private InvitesListPanel invitesListPanel;
	private Message context;	
	
	public AppointmentPanel(Appointment appointment,Model model, Message context,NewsPanel newsPanel) {
		super();
		this.context=context;
		this.model=model;
		model.addPropertyChangeListener(this);
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		setLayout(layout);
		/*
		c.gridx=3;
		c.gridy=0;
		c.gridwidth=1;
		c.gridheight=4;*/
		//add(newsPanel,c);
		
		c.gridheight=1;
		c.gridwidth=2;
		c.gridx=0;
		c.gridy=0;
		infoPanel = new AppointmentInfoPanel(this,model);
		add(infoPanel,c);
		
		c.gridwidth=4;
		c.gridx=2;
		invitesListPanel = new InvitesListPanel(this,model);
		add(invitesListPanel,c);
		
		c.anchor=GridBagConstraints.WEST;
		c.gridwidth=1;
		c.gridx=0;
		c.gridy=1;
		createButton = new JButton("Create appointment");
		if (appointment!=null)
			createButton.setText("Perform edit");
		add(createButton,c);
		c.gridx=1;
		editButton = new JButton("Enable editing");
		add(editButton,c);
		c.gridx=2;
		backButton = new JButton("Back");
		add(backButton,c);
		
		createButton.addActionListener(this);
		editButton.addActionListener(this);
		backButton.addActionListener(this);
		
		oldAppointment=appointment;
		updateToAppointment(oldAppointment);
		
		if(appointment==null)
			{
			isOwner=true;
			setEditable(true);
			}
		else
			{
			isOwner = appointment.ownerPersonID==model.getPersonID();
			setEditable(false);
			editButton.setEnabled(isOwner);
			System.out.println("Is owner: "+isOwner);
			}
		if (context==null)
			System.out.println("Message context is null");
		if(context!=null)
			{
			//ADD STUFF FOR MESSAGE CONTEXT
			int type=context.type;
			c.gridx=0;
			c.gridy=2;	
			if (type==TYPE.INVITATION)
				add(makeMessageComponent("Invitation to this to meeting. Is this ok?"),c);
			else if (type==TYPE.CHANGED)
				add(makeMessageComponent("An old appointment has been changed to this. Is this ok?"));
			else if (type==TYPE.DENIED)
				add(new JLabel(model.getPerson(context.auxField).email + " has denied this invitation."),c);
			else if (type==TYPE.LEFT)
				add(makeMessageComponent(model.getPerson(context.auxField).email + " is no longer participating in this."),c);
			else if (type==TYPE.CANCELLED)
				add(makeMessageComponent("This appointment is canceled."),c);
			else if (type==TYPE.DELETED)
				add(makeMessageComponent("You are deleted from this appointment."),c);
			
			c.gridx=0;
			c.gridy=3;
			if(context.auxString.trim()!="")
				add(new JLabel("Reason specified: "+context.auxString),c);
			
			c.gridx=0;
			c.gridy=4;
			if(context.type==TYPE.INVITATION || context.type==TYPE.CHANGED)
				{
				JButton button = new JButton("Accept Invitation");
				button.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					accept();
					deleteMessage();
				}});
				add(button,c);
				
				c.gridx=1;
				
				button = new JButton("Deny Invitation");
				button.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					deny();
					deleteMessage();
				}});
				add(button,c);
				}
			else
				{
				JButton button = new JButton("Delete message");
				button.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					deleteMessage();
				}});
				add(button,c);
				}
			
			
			}
	}
	private Component makeMessageComponent(String message)
		{
		return new JLabel(message);
		}
	private void accept()
		{
		model.gui_setAttendance(model.getPersonID(), oldAppointment.ownerPersonID, oldAppointment.appointmentID, STATUS.ACCEPTED, "");//Should check whether we were deleted in the mean time but whatever
		}
	private void deny()
		{
		model.gui_setAttendance(model.getPersonID(), oldAppointment.ownerPersonID, oldAppointment.appointmentID, STATUS.DENIED, JOptionPane.showInputDialog("Reason: "));//Should check whether we were deleted in the mean time but whatever
		}
	private void deleteMessage()//And close view.
		{
		model.gui_deleteMessage(context.messageID);
		setEditable(false);
		editButton.setEnabled(false);
		model.getGUI().showCalendar();
		}
	
	private void setEditable(boolean b)
		{
		isEditable=b;
		infoPanel.setEditable(b);
		invitesListPanel.setEditable(b);
		createButton.setEnabled(b);
		editButton.setEnabled(!b);
		}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(createButton))//CREATE 
			{
			int changedFromID=-1;
			if (oldAppointment!=null)
				changedFromID=oldAppointment.appointmentID;
			String location="";
			if(newAppointment.roomID==-1)
				location=newAppointment.locationName;
			if(newAppointment.startTime==null)
				{
				JOptionPane.showMessageDialog(null, "Start time not set correctly","Error",JOptionPane.ERROR_MESSAGE);
				return;
				}
			if(newAppointment.endTime==null)
				{
				JOptionPane.showMessageDialog(null, "End time not set correctly","Error",JOptionPane.ERROR_MESSAGE);
				return;
				}
			if(!newAppointment.endTime.after(newAppointment.startTime))
				{
				JOptionPane.showMessageDialog(null, "End time before start time","Error",JOptionPane.ERROR_MESSAGE);
				return;
				}
			if(newAppointment.subject==null)
				{
				JOptionPane.showMessageDialog(null, "You must have a subject","Error",JOptionPane.ERROR_MESSAGE);
				return;
				}
			if(newAppointment.subject=="")
				{
				JOptionPane.showMessageDialog(null, "You must have a subject","Error",JOptionPane.ERROR_MESSAGE);
				return;
				}
			boolean changed=true;
			if(oldAppointment!=null)
				{
				if(oldAppointment.subject.equals(newAppointment.subject) && oldAppointment.description.equals(newAppointment.description) && oldAppointment.startTime.equals(newAppointment.startTime) && oldAppointment.endTime.equals(newAppointment.endTime) && oldAppointment.roomID==newAppointment.roomID && oldAppointment.locationName.equals(location))
					changed=false;
				}
			if(changed)
				model.gui_setAppointment(changedFromID, newAppointment.startTime, newAppointment.endTime, newAppointment.subject, newAppointment.description, newAppointment.roomID, location);
			//calculate diff in invited people
				
			//Extract a list of participants and a list of statuses
			ArrayList<Integer> toBeAdded = invitesListPanel.getParticipants();
			ArrayList<Integer> toBeRemoved = new ArrayList<Integer>();
			int whichAppointmentID=model.getNextAppointmentID();
			
			if(oldAppointment!=null)//If changed, CHANGE messages are sent to ALL earlier invited persons by the SERVER(except those that were deleted by owner)
				{
				HashMap<Integer,Integer> statusMap = oldAppointment.getStatuses();
				
				Iterator<Entry<Integer,Integer>> it = statusMap.entrySet().iterator();
				while (it.hasNext())
					{
					Entry<Integer,Integer> entry = it.next();
					Integer personID = entry.getKey();
					Integer personStatus = entry.getValue();
					if (toBeAdded.contains(personID))
						{
						if (personStatus<=2 || changed)//If changed, we do not need to reset anything.
							toBeAdded.remove(personID);//Do not add the person if he was there before with a good status
						}
					else
						toBeRemoved.add(personID);//Remove the person if he was there before but not now
					}
				}
			if (!changed)//Send attendances for the old app
				{
				whichAppointmentID=oldAppointment.appointmentID;
				System.out.println("Changing attendances for old app");
				}
			
			for(int i=0; i<toBeAdded.size(); i++)
				{
				Integer personID = toBeAdded.get(i);
				if(personID!=model.getPersonID())//Not for owner, dude
					{
					System.out.println("set attendance for "+personID);
					model.gui_setAttendance(personID, model.getPersonID(), whichAppointmentID, STATUS.NOTREPLIED, "");
					}
				}
			for(int i=0; i<toBeRemoved.size(); i++)
				{
				Integer personID = toBeRemoved.get(i);
				System.out.println("Remove for "+personID);
				model.gui_setAttendance(personID, model.getPersonID(), whichAppointmentID, STATUS.DELETE, "");
				}
			if (changed==false)
				{
				if(toBeAdded.size()==0 && toBeRemoved.size()==0)
					JOptionPane.showMessageDialog(null,"There were no changes.","Result",JOptionPane.ERROR_MESSAGE);
				else
					JOptionPane.showMessageDialog(null,"Attendances changed.","Result",JOptionPane.PLAIN_MESSAGE);
				model.getGUI().showCalendar();
				}
			
			if(changed)//Now wait for a response
				{ 
				setEditable(false);
				editButton.setEnabled(false);
				}
			}
		else if (e.getSource().equals(editButton)) 
			{
			//invitesListPanel.setDefaultStatuses();
			setEditable(true);
			}
		else if (e.getSource().equals(backButton)) 
			{
			close();
			model.getGUI().showCalendar();
			}
		}
	public void close()
		{
		if (context!=null)//we didn't delete the message, pop it up again
			{
			model.getGUI().addMessage(context);
			}
		}
	public void updateToAppointment(Appointment a)
		{
		if(a!=null)
			newAppointment=new Appointment(a.ownerPersonID,-1,a.startTime,a.endTime,a.subject,a.description,a.roomID,a.locationName,-1,false);
		else
			newAppointment=new Appointment(model.getPersonID(),-1,null,null,"","",-1,"",-1,false);
		infoPanel.updateToAppointment(a,newAppointment);
		invitesListPanel.updateToAppointment(a,newAppointment);
		}

	@Override
	public void propertyChange(PropertyChangeEvent e)
		{
		if (e.getPropertyName().equals(CHANGE.APPOINTMENT) && isEditable==false)
			{
			Appointment oldValue = (Appointment)e.getOldValue();
			Appointment newValue = (Appointment)e.getNewValue();
			
			if (oldValue!=null && oldAppointment!=null)
				{
				if (oldValue.getKey().equals(oldAppointment.getKey()))
					{
					updateToAppointment(newValue);
					}
				}
			}
		
		}

	public void appointmentAddFailure()
		{
		JOptionPane.showMessageDialog(null,"Appointment failed due to room reservation","Result",JOptionPane.ERROR_MESSAGE);
		setEditable(true);
		}
	public void appointmentAddSuccess()
		{
		if (oldAppointment==null)
			JOptionPane.showMessageDialog(null,"Appointment created successfully, invitations sent.","Result",JOptionPane.PLAIN_MESSAGE);
		else
			JOptionPane.showMessageDialog(null,"Appointment changed successfully, new invitations sent.","Result",JOptionPane.PLAIN_MESSAGE);
		model.getGUI().showCalendar();
		}
	}
